//
// Created by 郝羽 on 2018/5/23.
//

#include "remote_address_list.hpp"

#include <arpa/inet.h>
#include <map>
#include <string>
#include <gio/gio.h>

#include "xcutil.h"
#include "xm_log.h"

constexpr int remote_addr_timeout = 10000;

struct remote_address {
    sockaddr_in sa;
    int64_t last_update_time;
};

struct remote_address_list {
    std::map<std::string, remote_address> addrs;
};

remote_address_list* remote_address_list_new() {
    auto ral = new remote_address_list();
    return ral;
}

void remote_address_list_del(remote_address_list* ral) {
    // auto it = ral->addrs.begin();

    delete ral;
}

void remote_address_list_update(remote_address_list* ral, sockaddr_in sa) {
    char key[128] = {0,};

    sprintf(key, "%s:%d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));

    std::string hint(key);

    auto it = ral->addrs.find(hint);

    if (it == ral->addrs.end()) {
        ral->addrs.emplace(hint, remote_address { .sa = sa, .last_update_time = get_timestamp_ms() });
        dbgi("remote address '%s' added", hint.c_str());
    } else {
        ral->addrs[hint].last_update_time = get_timestamp_ms();
    }
}

void remote_address_list_handle_timeout(remote_address_list* ral, int64_t now) {
    auto it = ral->addrs.begin();

    while (it != ral->addrs.end()) {
        auto it_cur = it++;
        auto ra = it_cur->second;
        if (now - ra.last_update_time > remote_addr_timeout) {
            dbgi("remote address '%s:%d' timeout", inet_ntoa(ra.sa.sin_addr), ntohs(ra.sa.sin_port));
            ral->addrs.erase(it_cur);
        }
    }
}

void remote_address_list_each(remote_address_list* ral, std::function<void(sockaddr_in)> callback) {
    for (auto it : ral->addrs) {
        auto ra = it.second;
        callback(ra.sa);
    }
}


